/*
 * Buffer.h
 *
 *  Created on: 2012-9-3
 *      Author: yangentao@gmail.com
 */

#ifndef BUFFER_H_
#define BUFFER_H_

#include <stack>
#include <vector>
#include <map>
#include <algorithm>

#include "../util/util.h"
#include "../win32/win32.h"
#include "ActionManager.h"
#include "Pos.h"
#include "TextListener.h"
#include "PosListener.h"

#include "LineManager.h"

using namespace std;

//IMPORTANT!!
//XXX if need removeXXXListener, vector<XXXListener*> should clone when fire!

class TextBuffer;

class AutoActionGroup {
private:
	TextBuffer* textBuffer;
public:
	AutoActionGroup(TextBuffer* textBuffer_);
	virtual ~AutoActionGroup();
};

class TextVector: public SplitVec<char> {
public:
	TextVector();
};

class TextBuffer: public ITextReplacable {
	friend class AutoActionGroup;
protected:
	TextVector text;
	Vector<TextListener*> textListeners;
	Vector<PosListener*> posListeners;
	ActionManager actionMgr;
	LineManager lineMgr;
	PosManager posMgr;
public:
	TextBuffer();
	virtual ~TextBuffer();
	void dump(){
		text.dump();
		lineMgr.dump();
	}
public:
	void addTextListener(TextListener* textListener);
	void addPosListener(PosListener* posListener);

	LineManager* getLineManager() {
		return &lineMgr;
	}
	/// Retrieving positions outside the range of the buffer works and returns 0
	char inline getChar(int position) const {
		return text.get(position);
	}
	String getCharRange(int position, int length) const;
	inline const char* BufferPointer() {
		return text.getBuffer();
	}
	int inline length() const {
		return text.length();
	}

	inline int getLineCount(){
		return lineMgr.count();
	}
	inline int getLineStart(size_t line){
		return lineMgr.getLineStart(line);
	}
	inline int findLine(int pos){
		return lineMgr.findLine(pos);
	}

	Pos inline createPos(int index) {
		if(index>=0 && index <= text.length()){
			return posMgr.createPos(index);
		}else{
			throw InvalidIndexException();
		}
	}

	void inline beginGroup() {
		actionMgr.beginGroup();
	}
	void inline endGroup() {
		actionMgr.endGroup();
	}
	void inline doAction(const Action& action) {
		actionMgr.doAction(action);
	}
	void inline undo() {
		actionMgr.undo();
	}
	void inline redo() {
		actionMgr.redo();
	}
	bool inline canUndo() {
		return actionMgr.canUndo();
	}
	bool inline canRedo() {
		return actionMgr.canRedo();
	}
	void inline clearUndoHistory() {
		actionMgr.clear();
	}
protected:
	//return old text
	String textReplace(int from, int len_, const String& newText);
};

#endif /* BUFFER_H_ */
